package com.wuage.infrastructure.utils;

import com.alibaba.fastjson.JSON;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import com.wuage.infrastructure.config.OssConfig;
import com.wuage.infrastructure.status.BizResultCode;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextStoppedEvent;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.net.URL;
import java.util.Date;

/**
 * @author Shynin
 * @version 1.0
 * @date 9/27/21 3:03 PM
 */
@Component
public class OssUtil implements InitializingBean, ApplicationListener<ApplicationEvent> {

    private static final Logger LOG       = LoggerFactory.getLogger(OssUtil.class);
    public static final String  FILE_NAME = "file-name";
    /**
     * oss配置属性文件
     */
    private static String       endPoint;
    /**
     * oss配置属性文件
     */
    private static String       accessKeyId;
    /**
     * oss配置属性文件
     */
    private static String       accessKeySecret;
    /**
     * oss配置属性文件
     */
    private static String       bucketName;
    /**
     * 图片url
     */
    private static String       imgUrl;

    private static OSSClient ossClient = null;


    @Autowired
    private OssConfig ossConfig;

    private OssUtil(){
    }

    /**
     * 容器启动初始化 OssClient
     */
    private void init() {
        try {

            accessKeyId = ossConfig.getAccessKeyId();
            accessKeySecret = ossConfig.getAccessKeySecret();
            bucketName = ossConfig.getBucketName();
            endPoint = ossConfig.getEndpoint();
            imgUrl = ossConfig.getUrl();
            LOG.info("try to decrypt db password with keycenter...");


            LOG.info("finish decrypt db password with keycenter: success!accessKeyId:" + accessKeyId
                    + ",accessKeySecret:" + accessKeySecret);
        } catch (Exception e) {
            LOG.error("decrypt db password error.", e);
            throw new IllegalStateException("KeyCenter decrypt db password error.");
        }

        if (ossClient == null) {
            ossClient = new OSSClient(endPoint, accessKeyId, accessKeySecret);
        }
        LOG.info("system load oss  configuration success  --> bucketName:{}", bucketName);
    }

    /**
     * 获取ossClient
     *
     * @return the ossClient
     */
    public static OSSClient getOssClient() {
        if (ossClient == null) {
            ossClient = new OSSClient(endPoint, accessKeyId, accessKeySecret);
        }
        return ossClient;
    }

    /**
     * 获取bucketName
     *
     * @return bucketName
     */
    public static String getBucketName() {
        return bucketName;
    }

    /**
     * @Description:上传文件
     * @author meng.liu
     * @date 2018年9月5日 下午2:21:49
     * @param byt
     * @param fileType
     * @param fileName
     * @return key
     */
    public static Response<String> upload(byte[] byt, String fileType, String fileName) {
        Response<String> result = new Response<>();
        if (byt == null || StringUtils.isBlank(fileType) || StringUtils.isBlank(fileName)) {
            return Response.error("param is null");
        }
        try {
            // 获取ossClient
            OSSClient ossClient = OssUtil.getOssClient();
            // 文件命名规则 获取当前系统时间纳秒
            // 存储到数据库的文件key
            String key = Long.toString(System.nanoTime());
            // 上传到oss文件名称
            String ossFileKey = key + "." + fileType;
            // {ObjectMetadata}oss用于用户自定义的元数据,这里将文件名称存入
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.addUserMetadata(FILE_NAME, fileName);
            ossClient.putObject(bucketName, ossFileKey, new ByteArrayInputStream(byt), objectMetadata);
            result.setData(key);
            return result;
        } catch (Exception e) {
            LOG.error("upload  exception", e);
            result.setMsg("upload is exception");
        }
        return result;
    }

    /**
     * @Description:根据文件key,文件类型获取临时文件路径
     * @author meng.liu
     * @date 2018年9月5日 下午2:22:50
     * @param fileKey
     * @param fileType
     * @param minutes (过期时间 ，可为空 默认20)
     * @return
     */
    public static Response<String> download(String fileKey, String fileType, Integer minutes) {
        Response<String> result = new Response<>();
        try {
            // 获取ossClient
            OSSClient ossclient = OssUtil.getOssClient();
            String ossFileKey = fileKey + "." + fileType;
            // 时间有效期默认 20 minute to expire 链接二十分钟有效
            Date expires = DateUtils.addMinutes(new Date(), minutes != null ? minutes : 20);
            GeneratePresignedUrlRequest urlRequest = new GeneratePresignedUrlRequest(OssUtil.getBucketName(),
                    ossFileKey);
            urlRequest.setExpiration(expires);
            // 获取文件url
            URL url = ossclient.generatePresignedUrl(urlRequest);
            result.setData(url.toString());
            return result;
        } catch (OSSException e) {
            LOG.error("download exception", e);
            result.setMsg("download exception");
        }
        return result;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        // 关闭ossclient
        if (event instanceof ContextClosedEvent) {
            ossClient.shutdown();
        }
        if (event instanceof ContextStoppedEvent) {
            ossClient.shutdown();
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        init();
    }

    /**
     * @Description:上传文件到 oss的auth目录中
     * @author meng.liu
     * @date 2018年9月5日 下午2:21:49
     * @param byt 文件字节
     * @param fileName 文件名字
     * @return key
     */
    public String uploadFile(byte[] byt, String fileName) {
        if (byt == null || StringUtils.isBlank(fileName)) {
            throw BizResultCode.PARAM_ERROR.toException();
        }
        try {
            // 获取ossClient
            OSSClient ossClient = OssUtil.getOssClient();
            // 文件命名规则 获取当前系统时间纳秒
            // 存储到数据库的文件key
            // String key = Long.toString(System.nanoTime());
            // 上传到oss文件名称
            //String ossFileKey = "auth/"+fileName;
            String ossFileKey = fileName;
            // {ObjectMetadata}oss用于用户自定义的元数据,这里将文件名称存入
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.addUserMetadata(FILE_NAME, fileName);
            PutObjectResult putRes = ossClient.putObject(bucketName, ossFileKey, new ByteArrayInputStream(byt),
                    objectMetadata);

            LOG.info("upload  putRes={}", JSON.toJSONString(putRes));
            return "https://" + imgUrl + "/" + ossFileKey;
        } catch (Exception e) {
            LOG.error("upload  exception", e);
            throw BizResultCode.UPLOAD_ERROR.toException();
        }
    }
}